/*
	Requirments:
	- jQuery library (http://jquery.com/)
	- excanvas.js (http://code.google.com/p/explorercanvas/) - For IE support.

	Options:
	-------------------------------------------
	- options.color - The initial pen color
	- options.width - The initial pen width
	- options.cWidth - The width of the canvas
	- options.cHeight - The height of the canvas
	
	Methods:
	-------------------------------------------
	- init(canvasId)					- Initializes the drawing area in the canvas with given ID. The <canvas> element must be already created and ready.
	- setColor(color)					- Sets the pen color. Accepted values: #RRGGBB, #RGB, RRGGBB, RGB or an object with elements r, g and b (0-255)
	- setWidth(width) 					- Sets the pen width. Accepted values: The width of the pen in pixels
	- getColor()						- Gets current pen color - object with elements r, g and b (0-255)
	- getwidth()						- Gets current pen width in pixels
	- clear()							- Clears the drawing board
	- getImage(fromFrame, toFrame)		- Returns the image in special format for replaying the drawing
	- replay(image)						- Replays the drawing of the image. Accepts the return value of getImage() method

*/

function drawingArea(options) {
	var _canvas, _ctx, $canvas;
	var _penDown = false;
	var _lastPos = false;
	var _readOnly = false;
	var that = this;
	var _canvas_offset = {top: 0, left: 0};

	var _hasChanges = true;
	var _imageCache = '';

	if (typeof options == 'undefined') var options = {};
	if (typeof options.color == 'undefined') options.color = '#000000';
	if (typeof options.width == 'undefined') options.width = 2;
	if (typeof options.cWidth == 'undefined') options.cWidth = false;
	if (typeof options.cHeight == 'undefined') options.cHeight = false;

	var _lastLineStartFrame = false;
	var _lastLineEndFrame = false;
	var _lastLineColor = options.color;
	var _lastLineWidth = options.width;

	var _frames = [];

	_lastColorPos = -1;
	_lastSpacePos = -1;
	_lastWidthPos = -1;

	var _addFrame = function(frameType, data) {
		switch(frameType) {
			case 'pixel':
				_lastColorPos = -1;
				_lastSpacePos = -1;
				_lastWidthPos = -1;

				_frames.push(data.x+':'+data.y);

				if (!_lastLineStartFrame) {
					_lastLineStartFrame = _frames.length-1;
					$canvas.trigger('lineStart', [_lastLineStartFrame, _lastLineColor, _lastLineWidth]);
				}

				_lastLineEndFrame = _frames.length;

				_hasChanges = true;
			break;
			case 'space':
				if (_lastSpacePos < 0) {
					_frames.push('_');
					_lastSpacePos = _frames.length-1;
				} else {
					_frames[_lastSpacePos] = '_';
				}
				_hasChanges = true;

				if (_lastLineStartFrame !== false && _lastLineEndFrame !== false) {
					$canvas.trigger('lineEnd', [_lastLineStartFrame, _lastLineEndFrame, _lastLineColor, _lastLineWidth]);

					_lastLineStartFrame = false;
					_lastLineEndFrame = false;
				}
			break;
			case 'color':
				if (_lastColorPos < 0) {
					_frames.push('#'+data);
					_lastColorPos = _frames.length-1;
				} else {
					_frames[_lastColorPos] = '#'+data;
				}
				_lastLineColor = options.color;
				_hasChanges = true;
			break;
			case 'width':
				if (_lastWidthPos < 0) {
					_frames.push('W'+data);
					_lastWidthPos = _frames.length-1;
				} else {
					_frames[_lastWidthPos] = 'W'+data;
				}
				_lastLineWidth = options.width;
				_hasChanges = true;
			break;
			default:
			break;
		}
	}

	this.init = function(cid) {
		_canvas = document.getElementById(cid);
		if (!_canvas) throw 'Canvas not found!';
		if (!_canvas.getContext) return false;
		$canvas = $(_canvas);

		var _canvas_offset = $canvas.offset();
		_canvas_offset.left = Math.round(_canvas_offset.left);
		_canvas_offset.top = Math.round(_canvas_offset.top);

		if (!options.cWidth) options.cWidth = $canvas.width();
		if (!options.cHeight) options.cHeight = $canvas.height();
		
		_ctx = _canvas.getContext('2d');
		_ctx.lineCap = "round";
		_ctx.lineJoin = "round";
		
		this.setColor(options.color);
		this.setWidth(options.width);

		$canvas
			.mousedown(function(e) {
				if (_readOnly) return;

				_penDown = true;
				
				var x = e.clientX-_canvas_offset.left+$(window).scrollLeft();
				var y = e.clientY-_canvas_offset.top+$(window).scrollTop();

				_ctx.beginPath();
				_ctx.moveTo(x, y);
				_ctx.lineTo(x, y);
				_ctx.closePath();
				_ctx.stroke();

				_lastPos = {x: x, y: y};

				_addFrame('pixel', _lastPos);

				_lastLineStartFrame = _frames.length-1;
				_lastLineColor = options.color;
				_lastLineWidth = options.width;
			})
			.mouseup(function() {
				if (_readOnly) return;

				_lastPos = false;
				_penDown = false;
				_addFrame('space');
			})
			.mouseleave(function() {
				if (_readOnly) return;

				_lastPos = false;
				_penDown = false;
				_addFrame('space');
			})
			.mousemove(function(e) {
				if (_readOnly) return;

				if (!_penDown || e.which != 1) return;

				_ctx.beginPath();
				
				if (!_lastPos) {
					_lastPos = {
						x: e.clientX - _canvas_offset.left + $(window).scrollLeft(),
						y: e.clientY - _canvas_offset.top + $(window).scrollTop()
					};
					return;
				}

				var _tmp_pos = {
					x: e.clientX-_canvas_offset.left+$(window).scrollLeft(),
					y: e.clientY-_canvas_offset.top+$(window).scrollTop()
				}

				_ctx.moveTo(_lastPos.x, _lastPos.y);
				_ctx.lineTo(_tmp_pos.x, _tmp_pos.y);

				_ctx.closePath();
				_ctx.stroke();

				_addFrame('pixel', _tmp_pos);

				_lastPos = _tmp_pos;
			});
	}

	this.replay = function(data) {
		data = data.split('.');
		var i = 0;
		var l = data.length-1;

		var prevPoint = false;

		var percent = 0;

		_readOnly = true;

		var _int = setInterval(function() {
		
			if (i > l) {
				_readOnly = false;
				clearInterval(_int);
				return;
			}

			var tmp = data[i].split(':');
			if (tmp.length == 2) {
				// draw the pixel					
				_ctx.beginPath();

				if (!prevPoint) {
					prevPoint = tmp;
					_ctx.moveTo(tmp[0], tmp[1]);
				} else {
					_ctx.moveTo(prevPoint[0], prevPoint[1]);
				}
				_ctx.lineTo(tmp[0], tmp[1]);
				prevPoint = tmp;

				_ctx.closePath();
				_ctx.stroke();
			}
			else if (data[i]=='_') {
				// end last line and begin from the next point
				prevPoint = false;
			}
			else if (data[i].match(/^\#/)) {
				that.setColor(data[i]);
			}
			else if (data[i].match(/^W/)) {
				that.setWidth(data[i].substring(1));
			}
			i++;
		}, 5);
	}

	this.setColor = function(color) {
		if (typeof color == 'string') {
			if (color.length != 3 && color.length != 6 && color.length != 4 && color.length != 7) {
				// invalid color
				return false;
			}
			var _obj = {};
			if (color.length == 4 || color.length == 7) {
				color = color.substring(1);
			}
			switch (color.length) {
				case 3:
					var r = color.substring(0,1);
					var g = color.substring(1,2);
					var b = color.substring(2,3);
					_obj.r = parseInt(r+r,16);
					_obj.g = parseInt(g+g,16);
					_obj.b = parseInt(b+b,16);
				break;
				case 6:
					_obj.r = parseInt(color.substring(0,2), 16);
					_obj.g = parseInt(color.substring(2,4), 16);
					_obj.b = parseInt(color.substring(4,6), 16);
				break;
			}
			
			color = _obj;
		}

		if (typeof color != 'object')
			return false;

		options.color = color;

		_ctx.strokeStyle = 'rgb('+options.color.r+','+options.color.g+','+options.color.b+')';

		var _r = options.color.r.toString(16);
		var _g = options.color.g.toString(16);
		var _b = options.color.b.toString(16);

		if (_r.length == 1) _r+=_r;
		if (_g.length == 1) _g+=_g;
		if (_b.length == 1) _b+=_b;

		_addFrame('color', _r+_g+_b);
	}

	this.setWidth = function(width) {
		options.width = width;
		_ctx.lineWidth = width;
		_addFrame('width', options.width);
	}

	this.getImage = function(fromFrame, toFrame) {
		var dontSlice = false;
		if (typeof fromFrame == 'undefined' && typeof toFrame == 'undefined') dontSlice = true;

		if (!dontSlice) {
			if (typeof fromFrame == 'undefined') var fromFrame = 0;
			if (typeof toFrame == 'undefined') var toFrame = _frames.length-1;

			var tmp = new Array();

			var _r = options.color.r.toString(16);
			var _g = options.color.g.toString(16);
			var _b = options.color.b.toString(16);

			if (_r.length == 1) _r+=_r;
			if (_g.length == 1) _g+=_g;
			if (_b.length == 1) _b+=_b;

			tmp.push('#'+_r+_g+_b);
			
			tmp.push('W'+options.width);

			var _part = _frames;

			//if (fromFrame >= toFrame) toFrame = fromFrame + 1;

			_part = _part.slice(fromFrame, toFrame);

			tmp = tmp.concat(_part);

			delete _part;

		} else {
			
			tmp = _frames;
			
		}

		if (_hasChanges) {
			_imageCache = tmp.join('.');
			_hasChanges = false;
		}
		
		delete tmp;
		
		return _imageCache;
	}

	this.getColor = function() {
		return options.color;
	}
	
	this.getWidth = function() {
		return options.width;
	}

	this.clear = function() {
		_ctx.clearRect(0,0,options.cWidth,options.cHeight);
	}
}
